package org.boulderfoodrescue.webapp.client;

import org.boulderfoodrescue.webapp.client.about.AboutPresenter;
import org.boulderfoodrescue.webapp.client.donors.DonorPresenter;
import org.boulderfoodrescue.webapp.client.events.DataState;
import org.boulderfoodrescue.webapp.client.events.LoginInfoUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.LoginInfoUpdatedHandler;
import org.boulderfoodrescue.webapp.client.events.MapsUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.MapsUpdatedHandler;
import org.boulderfoodrescue.webapp.client.header.HeaderPresenter;
import org.boulderfoodrescue.webapp.client.header.HeaderView;
import org.boulderfoodrescue.webapp.client.home.HomePresenter;
import org.boulderfoodrescue.webapp.client.home.HomeView;
import org.boulderfoodrescue.webapp.client.loadingdialog.LoadingDialog;
import org.boulderfoodrescue.webapp.client.managers.LocationInfoManager;
import org.boulderfoodrescue.webapp.client.managers.LoginInfoManager;
import org.boulderfoodrescue.webapp.client.managers.MapsApiManager;
import org.boulderfoodrescue.webapp.client.managers.PickupManager;
import org.boulderfoodrescue.webapp.client.managers.TimeSlotManager;
import org.boulderfoodrescue.webapp.client.managers.UserAccountManager;
import org.boulderfoodrescue.webapp.client.navigation.NavigationPresenter;
import org.boulderfoodrescue.webapp.client.navigation.NavigationView;
import org.boulderfoodrescue.webapp.client.options.OptionsPresenter;
import org.boulderfoodrescue.webapp.client.pickups.PickupPresenter;
import org.boulderfoodrescue.webapp.client.recipients.RecipientPresenter;
import org.boulderfoodrescue.webapp.client.resources.Resources;
import org.boulderfoodrescue.webapp.client.rpc.LocationServiceAsync;
import org.boulderfoodrescue.webapp.client.rpc.LoginServiceAsync;
import org.boulderfoodrescue.webapp.client.rpc.PickupServiceAsync;
import org.boulderfoodrescue.webapp.client.rpc.TimeSlotServiceAsync;
import org.boulderfoodrescue.webapp.client.rpc.UserAccountsServiceAsync;
import org.boulderfoodrescue.webapp.shared.LoginInfo;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;

public class AppController implements ValueChangeHandler<String>{
	/* Event Bus for passing events between classes */
	private final EventBus eventBus;

	/* RPC Service Classes */
	private final LoginServiceAsync loginRPC;
	private final UserAccountsServiceAsync userRPC;
	private final LocationServiceAsync donorRPC;
	private final TimeSlotServiceAsync timeSlotRPC;
	private final PickupServiceAsync pickupRPC;

	/* Data Managers */
	private final MapsApiManager mapsApiManager;
	private final LoginInfoManager loginInfoManager;
	private final UserAccountManager userAccountManager;
	private final LocationInfoManager donorInfoManager;
	private final TimeSlotManager timeSlotManager;
	private final PickupManager pickupManager;

	/* Load dialog that is displayed at initilization */
	private final LoadingDialog dlg = new LoadingDialog();


	/* UI Elements */
	private DockLayoutPanel dock;
	private final FlowPanel container = new FlowPanel();

	public AppController(LoginServiceAsync loginRPC, UserAccountsServiceAsync userRPC, 
			LocationServiceAsync donorRPC, TimeSlotServiceAsync timeSlotRPC, PickupServiceAsync pickupRPC, EventBus eventbus)
	{
		this.eventBus = eventbus;
		this.loginRPC = loginRPC;
		this.userRPC = userRPC;
		this.donorRPC = donorRPC;
		this.timeSlotRPC = timeSlotRPC;
		this.pickupRPC = pickupRPC;
		bind();
		injectCss();
		mapsApiManager = new MapsApiManager(eventBus);
		loginInfoManager = new LoginInfoManager(loginRPC, eventBus);
		userAccountManager = new UserAccountManager(userRPC, eventBus);
		donorInfoManager = new LocationInfoManager(donorRPC, eventBus);
		timeSlotManager = new TimeSlotManager(timeSlotRPC, eventBus);
		pickupManager = new PickupManager(pickupRPC, eventBus);

		eventBus.fireEvent(new MapsUpdatedEvent(MapsUpdatedEvent.ApiState.Loading));
	}

	private void bind()
	{
		History.addValueChangeHandler(this);
		eventBus.addHandler(MapsUpdatedEvent.getType(),
				new MapsUpdatedHandler(){
			@Override
			public void onMapsApiLoadSuccess(MapsUpdatedEvent event) {
				dlg.setLoadingText("Loading User Data");
				eventBus.fireEvent(new LoginInfoUpdatedEvent(DataState.Loading));
			}
			@Override
			public void onMapsApiLoadStart(MapsUpdatedEvent event) {
				dlg.setLoadingText("Loading Google Maps");
				dlg.center();
			}
			@Override
			public void onMapsApiLoadFailed(MapsUpdatedEvent event) {
				Window.alert("Error: Failed to load Google Maps Api. Check your internet connection.");
			}
		});

		eventBus.addHandler(LoginInfoUpdatedEvent.getType(), 
				new LoginInfoUpdatedHandler(){
			@Override
			public void onLoginInfoLoadSuccess(LoginInfo loginInfo) {
				dlg.setLoadingText("Initilizing User Interface");
				initUserInterface();
			}
			@Override
			public void onLoginInfoLoading() {
			}
			@Override
			public void onLoginInfoLoadFailed() {
				Window.alert("Error: Failed to load user data. check your internet connection.");
			}
		});
	}

	private void injectCss()
	{
		Resources.INSTANCE.style().ensureInjected();
		Resources.INSTANCE.common().ensureInjected();
		Resources.INSTANCE.calendarCss().ensureInjected();
		Resources.INSTANCE.nav().ensureInjected();
		Resources.INSTANCE.profileSidebar().ensureInjected();
		Resources.INSTANCE.ops().ensureInjected();
		Resources.INSTANCE.timepicker().ensureInjected();
		Resources.INSTANCE.menubar().ensureInjected();
		Resources.INSTANCE.customTable().ensureInjected();
		Resources.INSTANCE.customSelector().ensureInjected();
	}

	private void initUserInterface()
	{
		RootLayoutPanel root = RootLayoutPanel.get();
		HeaderPresenter headerPresenter = new HeaderPresenter(new HeaderView());
		NavigationPresenter navigationPresenter = new NavigationPresenter(new NavigationView());
		dock = new DockLayoutPanel(Unit.EM);
		root.add(dock);
		dock.addNorth(headerPresenter.getWidget(), 5.25);
		dock.addNorth(navigationPresenter.getWidget(), 1.875);
		dock.add(container);
		dlg.hide();
		changeBasePage(History.getToken());
		root.addStyleName(Resources.INSTANCE.common().main_page());
	}

	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		changeBasePage(event.getValue());
	}

	private void changeBasePage(String token)
	{
		if (token != null) {
			Presenter presenter = null;
			LoginInfo loginInfo = LoginInfoManager.getLoginInfo();

			if(token.contains("about"))
				presenter = new AboutPresenter(eventBus);
			else if(token.contains("options") && loginInfo.isLoggedIn())
				presenter = new OptionsPresenter(eventBus);
			else if(token.contains("pickups") && loginInfo.isLoggedIn())
				presenter = new PickupPresenter(eventBus, token);
			else if(token.contains("donors") && loginInfo.isLoggedIn())
				presenter = new DonorPresenter(eventBus, token);
			else if(token.contains("recipients") && loginInfo.isLoggedIn())
				presenter = new RecipientPresenter(eventBus, token);
			else
				presenter = new HomePresenter(eventBus, new HomeView());
			if (presenter != null) {
				container.clear();
				container.add(presenter.getWidget());
			}
		}
	}
}
